-module( kinematics_worker ).

-export( [start/3] ).

-record( worker, { bounds, tree, defaultCell } ).


start( Bounds, Tree, DefaultCell ) when is_tuple(Bounds), is_pid(DefaultCell) ->
  State = #worker{ bounds=Bounds, tree=Tree, defaultCell=DefaultCell },
  loop( State ).
  
  
  
loop( State = #worker{} ) ->
  receive
    { assign_cell, Object, Pos } ->
      Object ! { cell_assigned, findCell( State, Pos ) },
      loop( State );
      
    { propagate_to_box, Box, Msg } ->
      propagateToBoxInWorld( State, Box, Msg ),
      loop( State );
      
    { propagate_to_all, Msg } ->
      propagateToAllInWorld( State, Msg ),
      loop( State );
      
    %Debug
    M ->
      error_logger:error_msg( "Unknown msg ~p\n", [M] ),
      exit( unknown_msg )
  end.



findCell( State = #worker{ bounds = Bounds }, Pos ) ->
  case geom:boxIn( Bounds, Pos ) of
    true ->
      octree:walkPoint( State#worker.tree, Pos, fun( X ) -> X end );
    false -> 
      error_logger:warning_msg( "Object outta world: ~p\n", [ Pos ] ),
      { Bounds, State#worker.defaultCell }
  end.

  
  
propagateToBoxInWorld( State, Box, Msg ) ->
  M = { propagate, Msg },
  F = fun( { _CellBox, CellPid }, A ) ->
    CellPid ! M,
    A
  end,
  octree:walkBox( State#worker.tree, Box, F, undefined ),
  State#worker.defaultCell ! M.



propagateToAllInWorld( State, Msg ) ->
  M = { propagate, Msg },
  F = fun( { _CellBox, CellPid }, A ) ->
    CellPid ! M,
    A
  end,
  octree:walkAllLeafs( State#worker.tree, F, undefined ),
  State#worker.defaultCell ! M.
